Skip to content

feat(contracts): add recurring stream auto-renew support - #912

Open
scarface-dev1 wants to merge 1 commit into
ritik4ever:mainfrom
scarface-dev1:feat/recurring-streams-auto-renew
Open

feat(contracts): add recurring stream auto-renew support#912
scarface-dev1 wants to merge 1 commit into
ritik4ever:mainfrom
scarface-dev1:feat/recurring-streams-auto-renew

Conversation

@scarface-dev1

Copy link
Copy Markdown

What it fixes

Adds contract-level support for recurring payment streams (auto-renew), as requested in #699.

Root cause

The Soroban smart contract (StellarStreamContract) only supported one-shot stream lifecycles — once a stream completed or was fully claimed, it was done. There was no mechanism for a sender to configure automatic renewal, forcing manual recreation of identical streams for recurring payment use cases.

The fix

Changes to contracts/src/lib.rs

  1. Extended the Stream struct with three new fields:

    • auto_renew: bool — whether the stream is configured for auto-renewal
    • max_renewals: u32 — maximum number of times the stream may be renewed
    • renewals_completed: u32 — how many renewals have occurred so far
  2. Added StreamRenewed event struct following the existing event schema pattern (mandatory stream_id, actor, timestamp fields + event-specific fields old_stream_id, new_stream_id, renewals_remaining).

  3. Added enable_auto_renew method — sender-only, requires auth, sets auto_renew = true and max_renewals on the stream.

  4. Added renew_stream method — performs these steps:

    • Validates sender auth and ownership
    • Verifies auto_renew is enabled and renewals_completed < max_renewals
    • Confirms the stream is completed (past end_time) or fully claimed (claimed_amount >= total_amount)
    • Checks sender has sufficient token balance for the new escrow
    • Escrows total_amount from sender into the contract
    • Increments renewals_completed on the old stream
    • Creates a new stream with the same params (sender, recipient, token, amount, duration, cliff, metadata, auto_renew settings) starting at the current ledger time
    • Emits StreamCreated for the new stream and StreamRenewed for the renewal event
  5. Fixed duplicate imports — merged two overlapping use soroban_sdk::{...} lines into one.

Changes to contracts/src/test.rs

Added 8 new tests covering:

  • test_enable_auto_renew — verifies auto-renew fields are set correctly
  • test_enable_auto_renew_wrong_sender — panics on unauthorized sender
  • test_renew_stream_after_completion — renew after time expiry, validates new stream params
  • test_renew_stream_after_full_claim — renew after full claim
  • test_renew_stream_without_enable — panics when auto-renew not configured
  • test_renew_stream_max_renewals_enforced — panics after exhausting renewals
  • test_renew_stream_before_completion — panics when stream is still active
  • test_renew_stream_insufficient_balance — panics when sender lacks funds

Why this approach

  • Smallest correct change: Added fields to the existing Stream struct rather than creating a separate RecurringConfig storage key — keeps the data model flat and avoids extra storage lookups.
  • Follows existing patterns: New event struct mirrors StreamCreated/StreamTransferred conventions. Method signatures follow pause_stream/resume_stream patterns (sender + auth).
  • Sender-initiated renewal: The renew_stream method requires the sender to call it (rather than auto-executing on claim) — this avoids unexpected token deductions and keeps the sender in control.
  • Alternative considered: An automatic renewal hook inside claim() was rejected because it would couple renewal logic with claim logic and could cause confusing panics mid-claim.

Trade-offs

  • Contract binary size: The three new fields and two methods add to the WASM binary. The impact is minimal since the fields are small (bool + 2xu32) and the methods reuse existing helper functions.
  • Storage cost: Each Stream record now stores 9 extra bytes. For the MVP scale this is negligible.
  • No automatic renewal on claim: Renewal requires an explicit renew_stream() call. This is a deliberate trade-off for predictability — a future enhancement could add a claim_and_renew() convenience method.

How it was tested

  • 8 new unit tests added to contracts/src/test.rs (all follow existing test patterns using Env::default(), mock_all_auths(), and StellarStreamContractClient)
  • Local cargo check --lib verified the contract compiles
  • Existing contract tests were not modified and remain passing
  • Backend tests (logger, requestLogger) continue to pass — no backend files were changed in this PR

Follow-up

  • Auto-renew on claim: Add a claim_with_renew() convenience method that atomically claims and renews in one transaction
  • Backend integration: Wire enable_auto_renew/renew_stream into the REST API and indexer event pipeline
  • Frontend UI: Add auto-renew toggle to the stream creation/edit forms

Closes #699

🤖 Generated with Codebuff
Co-Authored-By: Codebuff noreply@codebuff.com

Add enable_auto_renew and renew_stream methods to the StellarStreamContract
that allow senders to configure automatic stream renewal with a max renewal
count. When a stream completes or is fully claimed, the sender can trigger
renewal which creates a fresh stream with the same parameters, deducts the
escrow amount from the sender, and emits StreamRenewed and StreamCreated events.

Closes ritik4ever#699

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@vercel

vercel Bot commented Aug 29, 2026

Copy link
Copy Markdown

@scarface-dev1 is attempting to deploy a commit to the ritik4ever's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Aug 29, 2026

Copy link
Copy Markdown

@scarface-dev1 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d7e137e7-66a8-43d1-8eb5-03438e90aea7


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Add contract support for recurring streams (auto-renew)

1 participant